package com.fc.library.fresco

import android.content.Context
import android.graphics.Bitmap
import android.graphics.drawable.Animatable
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Handler
import android.os.Looper
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import com.facebook.cache.common.CacheKey
import com.facebook.cache.common.SimpleCacheKey
import com.facebook.common.references.CloseableReference
import com.facebook.drawee.controller.BaseControllerListener
import com.facebook.drawee.drawable.ScalingUtils
import com.facebook.drawee.generic.RoundingParams
import com.facebook.drawee.view.SimpleDraweeView
import com.facebook.imagepipeline.bitmaps.PlatformBitmapFactory
import com.facebook.imagepipeline.common.ResizeOptions
import com.facebook.imagepipeline.image.ImageInfo
import com.facebook.imagepipeline.request.BasePostprocessor
import com.facebook.imagepipeline.request.ImageRequest
import com.facebook.imagepipeline.request.ImageRequestBuilder
import com.fc.library.fresco.SimpleFresco.isInit

/**
 * Created by fc on 2017/11/14.
 */
class FrescoImageLoader : IFrescoImageLoader {

    private var loaderData: LoaderData? = null
    private val lock = java.lang.Object()
    private val mainThread = Handler(Looper.getMainLooper())


    override fun init(context: Context) {
        SimpleFresco.initialize(context)
    }

    override fun with(context: Context): IFrescoImageLoader {
        synchronized(lock) {
            while (loaderData != null) {
                try {
                    lock.wait(10000)
                } catch (e: InterruptedException) {
                    e.printStackTrace()
                }

            }
        }
        loaderData = LoaderData()
        loaderData?.context = context
        return this
    }


    override fun getView(context: Context): View {
        if (!isInit())
            return ImageView(context)
        return SimpleDraweeView(context)
    }

    override fun setPlaceHolder(drawable: Drawable): IFrescoImageLoader {
        loaderData?.placeDrawable = drawable
        return this
    }

    override fun setPlaceHolder(id: Int): IFrescoImageLoader {
        loaderData?.placeResource = id
        return this
    }

    override fun transform(transform: Transform): IFrescoImageLoader {
        loaderData?.transform = transform
        return this
    }

    override fun load(uri: Uri): IFrescoImageLoader {
        loaderData?.uri = uri
        return this
    }

    override fun load(id: Int): IFrescoImageLoader {
        loaderData?.imageId = id
        return this
    }

    override fun small(uri: Uri): IFrescoImageLoader {
        loaderData?.small = uri
        return this
    }

    override fun resize(width: Int, height: Int): IFrescoImageLoader {
        loaderData?.width = width
        loaderData?.height = height
        return this
    }

    override fun setScaleType(scaleType: ImageView.ScaleType): IFrescoImageLoader {
        loaderData?.scaleType = scaleType
        return this
    }

    override fun wrapContent(): IFrescoImageLoader {
        loaderData?.isWrapContent = true
        return this
    }

    private fun notifyThread() {
        if (loaderData != null) {
            loaderData = null
            synchronized(lock) {
                lock.notifyAll()
            }
        }
    }
    override fun into(view: View) {
        if (!isInit()) {
            notifyThread()
            return
        }
        val data = LoaderData(loaderData!!)
        if (view is SimpleDraweeView) {
            val draweeView = view
            if (!data.isShowAnimation)
                draweeView.getHierarchy().setFadeDuration(0)
            draweeView.getHierarchy().reset()
            if (data.scaleType != null)
                draweeView.getHierarchy().setActualImageScaleType(changeScaleType(data.scaleType!!))
            if (data.placeResource != 0)
                draweeView.getHierarchy().setPlaceholderImage(data.placeResource)
            if (data.placeDrawable != null)
                draweeView.getHierarchy().setPlaceholderImage(data.placeDrawable)
            var requestBuilder: ImageRequestBuilder?
            if (data.imageId != 0) {
                data.uri = Uri.parse(SimpleFresco.getFrescoResUri(data.context, data.imageId))
            }
            if (data.width != 0 && data.height != 0) {
                requestBuilder = ImageRequestBuilder.newBuilderWithSource(data.uri)
                        .setResizeOptions(ResizeOptions(data.width, data.height))
            } else {
                requestBuilder = ImageRequestBuilder.newBuilderWithSource(data.uri)
            }
            if (data.transform != null) {
                if (!data.transform!!.isNewBitmap()) {
                    requestBuilder!!.setPostprocessor(object : BasePostprocessor() {
                        override fun process(bitmap: Bitmap?) {
                            data.transform!!.transform(bitmap!!)
                        }

                        override fun getPostprocessorCacheKey(): CacheKey? {
                            return SimpleCacheKey(data.uri.toString())
                        }
                    })
                } else {
                    requestBuilder!!.setPostprocessor(object : BasePostprocessor() {
                        override fun process(sourceBitmap: Bitmap, bitmapFactory: PlatformBitmapFactory): CloseableReference<Bitmap>? {
                            if (data.width != 0 && data.height != 0) {
                                var bitmapRef: CloseableReference<Bitmap>? = null
                                try {
                                    bitmapRef = bitmapFactory.createBitmap(
                                            data.width, data.height, sourceBitmap.config)
                                    data.transform!!.transform(bitmapRef!!.get(), sourceBitmap)
                                    return CloseableReference.cloneOrNull(bitmapRef)
                                } finally {
                                    CloseableReference.closeSafely(bitmapRef)
                                }

                            } else {
                                return super.process(sourceBitmap, bitmapFactory)
                            }
                        }

                        override fun getPostprocessorCacheKey(): CacheKey? {
                            return SimpleCacheKey(data.uri.toString())
                        }
                    })

                }
            }

            val builder = SimpleFresco.newDraweeControllerBuilder(data.context)
                    .setOldController(draweeView.getController())
                builder.setLowResImageRequest(ImageRequest.fromUri(data.small))
            builder.setImageRequest(requestBuilder!!.build())
            if (data.isWrapContent || data.callback != null) {
                val controllerListener = object : BaseControllerListener<ImageInfo>() {
                    override fun onFinalImageSet(id: String?, imageInfo: ImageInfo?, animatable: Animatable?) {
                        super.onFinalImageSet(id, imageInfo, animatable)
                        if (data.isWrapContent) {
                            view.post {
                                var params: ViewGroup.LayoutParams? = view.layoutParams
                                if (params == null) {
                                    params = ViewGroup.LayoutParams(Util.Div(imageInfo!!.width), Util.Div(imageInfo.height))
                                } else {
                                    params.height = Util.Div(imageInfo!!.height)
                                    params.width = Util.Div(imageInfo.width)
                                }
                                view.layoutParams = params
                            }
                        }
                        if (data.callback != null)
                            data.callback!!.onFinal(id!!, imageInfo!!.width, imageInfo.height)

                    }

                    override fun onFailure(id: String?, throwable: Throwable?) {
                        super.onFailure(id, throwable)
                        if (data.callback != null)
                            data.callback!!.onFailed(id!!, throwable!!)
                    }
                }
                builder.setControllerListener(controllerListener)
            }
            if (data.leftTopCorner != 0.0f|| data.leftBottomCorner != 0.0f
                    || data.rightTopCorner != 0.0f || data.rightBottomCorner != 0.0f ) {
                val roundingParams = RoundingParams.fromCornersRadii(
                        data.leftTopCorner, data.rightTopCorner,
                        data.rightBottomCorner, data.leftBottomCorner)
                draweeView.getHierarchy().setRoundingParams(roundingParams)
            }

            if (data.circleParams != null) {
                val params = RoundingParams.fromCornersRadius(data.circleParams!!.getRadius().toFloat())
                params.roundAsCircle = true
                draweeView.getHierarchy().setRoundingParams(params)
            }
            if (Looper.myLooper() == Looper.getMainLooper())
                draweeView.setController(builder.build())
            else
                mainThread.post { draweeView.setController(builder.build()) }
        } else {
            notifyThread()
            throw RuntimeException("the view must be SimpleDraweeView in fresco")
        }
        notifyThread()
    }

    private fun changeScaleType(scaleType: ImageView.ScaleType): ScalingUtils.ScaleType {
        when (scaleType) {
            ImageView.ScaleType.FIT_XY -> return ScalingUtils.ScaleType.FIT_XY
            ImageView.ScaleType.FIT_CENTER -> return ScalingUtils.ScaleType.FIT_CENTER
            ImageView.ScaleType.CENTER -> return ScalingUtils.ScaleType.CENTER
            ImageView.ScaleType.CENTER_CROP -> return ScalingUtils.ScaleType.CENTER_CROP
            ImageView.ScaleType.CENTER_INSIDE -> return ScalingUtils.ScaleType.CENTER_INSIDE
            ImageView.ScaleType.FIT_START -> return ScalingUtils.ScaleType.FIT_START
            else -> {
            }
        }
        return ScalingUtils.ScaleType.CENTER
    }

    override fun destroy() {
        notifyThread()
        SimpleFresco.destroy()
    }
}